#include "./rf_task.h"
#include "../driver/cmd_uart.h"
#include <string.h>
#include "../conn/proto.h"
#include "../utils/decode.h"

namespace task {

using namespace driver;
using namespace utils;

bool RfTask::poll() {
    return rfUart->poll(m_bw, 50);
}

uint8_t RfTask::take_if_not_empty() {
    uint8_t v = m_bw.buf[0];
    m_bw.buf ++;
    m_bw.len --;
    return v;
}

uint8_t RfTask::take(uint8_t *dest, uint8_t len) {
    if (len > m_bw.len) {
        len = m_bw.len;
    }
    memcpy(dest, m_bw.buf, len);
    m_bw.buf += len;
    m_bw.len -= len;
    return len;
}

bool RfTask::sync(Frame &frame) {
    uint8_t head = take_if_not_empty();
    if (head != RfUart::HEAD) {
        return false;
    }

    uint8_t info[4];
    uint8_t index = 0;
    for (; index < 4;) {
        if (is_empty() && (!poll())) {
            return false;
        }
        uint8_t n = take(info + index, 4 - index);
        index += n;
    }

    frame.type = info[0];
    frame.cmd = info[1];
    frame.data_len = decode<uint16_t>(info + 2);
    return true;
}

void RfTask::exec_once() {
    Frame frame;
    if (!sync(frame)) {
        cmdUart->log("sync fail");
        return;
    }
    uint8_t len = frame.data_len + 2;
    uint8_t index = 0;

    if ((m_recv_index + len) >= RECV_BUF_SIZE) {
        m_recv_index = 0;
    }
    frame.data = m_recv_buf + m_recv_index;

    for (; index < len; ) {
        if (is_empty() && (!poll())) {
            cmdUart->log("data fail");
            return;
        }
        uint8_t n = take(frame.data + index, len - index);
        index += n;
    }

    uint8_t s = frame.type + frame.cmd
        + ((frame.data_len >> 8) & 0xFF) 
        + (frame.data_len & 0xFF);

    s += alg::sum_add(frame.data, frame.data_len);
    if (s != frame.data[frame.data_len]) {
        cmdUart->log("sum fail");
        return;
    }

    if (RfUart::END != frame.data[frame.data_len + 1]) {
        cmdUart->log("end fail");
        return;
    }

    m_recv_index += len;

    on_recv(frame);
}

void RfTask::on_recv(const Frame &frame) {

    switch (frame.type) {
        case RfUart::TYPE_NOTIFY:
            utils::ByteView bw;
            bw.buf = frame.data;
            bw.len = frame.data_len;
            cmdUart->write_notify(
                conn::notify::RF_NOTIFY,
                frame.cmd,
                bw
            );
        break;

        case RfUart::TYPE_RES: 
            m_res_mq.post(frame); 
        break;
    }
}

struct PollRfidTask : public rtos::Thread<PollRfidTask, 1024, osPriorityHigh2> {

    void  run() {
        Frame frame;
        for (;;) {
            rfTask->request(frame, 0x22);
            osDelay(300);
        }
    }
};

utils::Object<PollRfidTask> pollRfidTask;

void RfTask::run() {
    pollRfidTask->start();
    for (;;) {
        rfUart->poll(m_bw);
        for (; !is_empty();) {
            exec_once();
        }
    }
}



}


